package com.ice.work.moment.crawler.processor;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.honeybee.cloud.framework.common.enums.DataStatusEnum;
import com.honeybee.cloud.framework.common.idwork.IdWorker;
import com.ice.work.moment.crawler.service.IShareService;
import com.ice.work.moment.crawler.service.ITradingService;
import com.ice.work.moment.facade.crawler.analytical.ShareAnalyticalObject;
import com.ice.work.moment.facade.crawler.dto.ShareDTO;
import com.ice.work.moment.facade.crawler.enums.ShareEnum;
import com.ice.work.moment.facade.crawler.mapper.AnalyticalObjectConvertMapper;
import com.ice.work.moment.facade.crawler.model.Share;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description A股
 * @Author DELL
 * @Create 2019-04-29
 * @Since 1.0.0
 */
@Slf4j
@Component
@SuppressWarnings("all")
public class ShareProcessor extends BaseProcessor implements PageProcessor {

    @Autowired
    private IdWorker idWorker;
    @Autowired
    private IShareService shareService;
    @Autowired
    private ITradingService tradingService;

    @Override
    public void process(Page page) {
        try {
            Html html = page.getHtml();
            log.info("股票列表原文:{}", html.get());
            List<Selectable> trSelectableList = html.xpath("//*[@id='content']/table[2]/tbody/tr").nodes();
            if (CollectionUtils.isEmpty(trSelectableList) || CollectionUtils.size(trSelectableList) == 1) {
                log.info("无法获得股票列表原文");
                return;
            }
            int i = 1;
            List<ShareAnalyticalObject> shareAnalyticalObjects = Lists.newArrayList();
            do {
                Selectable trSelectable = trSelectableList.get(i);
                log.info("爬取股票列表内容:{}", trSelectable.get());
                ShareAnalyticalObject shareAnalyticalObject = new ShareAnalyticalObject();
                shareAnalyticalObject = getValues(shareAnalyticalObject, trSelectable);
                shareAnalyticalObjects.add(shareAnalyticalObject);
                log.info("股票列表内容处理结果:{}", shareAnalyticalObjects);
                i++;
            } while (i < trSelectableList.size());
            if (CollectionUtils.isEmpty(shareAnalyticalObjects)) {
                log.error("无法获得股票列表解析数据");
                return;
            }
            Map<String, ShareAnalyticalObject> shareMap = shareAnalyticalObjects.stream().collect(Collectors.toMap(ShareAnalyticalObject::getCode, a -> a, (k1, k2) -> k1));
            Set<String> codes = shareAnalyticalObjects.stream().map(ShareAnalyticalObject::getCode).collect(Collectors.toSet());
            List<ShareDTO> shareDTOList = shareService.findByShareCodes(codes);
            shareDTOList = Optional.ofNullable(shareDTOList).orElse(Lists.newArrayList());
            Map<String, ShareDTO> shareDTOMap = shareDTOList.stream().collect(Collectors.toMap(ShareDTO::getCode, a -> a, (k1, k2) -> k1));

            List<Share> shares = Lists.newArrayList();
            shareMap.forEach((key, value) -> {
                Share share = AnalyticalObjectConvertMapper.INSTANCE.toModel(value);
                ShareDTO shareDTO = shareDTOMap.get(key);
                if (Objects.isNull(shareDTO)) {
                    share.setId(idWorker.nextId());
                    share.setDataStatus(DataStatusEnum.VALID.key);
                    share.setCreateAt(new Date());
                } else {
                    share.setId(shareDTO.getId());
                }
                shares.add(share);

            });
            if (CollectionUtils.isNotEmpty(shares)) {
                shareService.saveOrUpdate(shares);
            }
        } catch (Exception e) {
            log.error("爬取股票列表异常", e);
        }

    }


    /**
     * 获取列值
     *
     * @param trSelectable
     * @return
     */
    private ShareAnalyticalObject getValues(ShareAnalyticalObject obj, Selectable trSelectable) {
        Class clazz = obj.getClass();
        Field[] fields = ReflectUtil.getFields(clazz);
        Method[] methods = ReflectUtil.getMethods(clazz);
        Map<String, Field> fieldMap = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, a -> a, (k1, k2) -> k1));
        Map<String, Method> methodMap = Arrays.stream(methods).collect(Collectors.toMap(Method::getName, a -> a, (k1, k2) -> k1));
        List<Selectable> tdSelectableList = trSelectable.xpath("//td").nodes();
        Map<Integer, String> resultMap = Maps.newConcurrentMap();
        for (int j = 0; j < tdSelectableList.size(); j++) {
            try {
                Selectable tdSelectable = tdSelectableList.get(j);
                //获取内容
                String value = null;
                List<Selectable> nobrSelectableList = tdSelectable.xpath("//nobr").nodes();
                if (CollectionUtils.isNotEmpty(nobrSelectableList)) {
                    for (Selectable nobrSelectable : nobrSelectableList) {
                        List<Selectable> aSelectableList = nobrSelectable.xpath("//a").nodes();
                        if (CollectionUtils.isNotEmpty(aSelectableList)) {
                            value = nobrSelectable.xpath("//a/text()").get();
                        }
                        if (StringUtils.isEmpty(value)) {
                            value = tdSelectable.xpath("//nobr/text()").get();
                        }
                        if (StringUtils.isEmpty(value)) {
                            value = trSelectable.xpath("//td/text()").nodes().get(j).get();
                        }
                        continue;
                    }
                    resultMap.put(j,StrUtil.trim(value));
                    continue;
                }
                List<Selectable> fontelectableList = tdSelectable.xpath("//font").nodes();
                if (CollectionUtils.isNotEmpty(fontelectableList)) {
                    for (Selectable fontelectable : fontelectableList) {
                        value = tdSelectable.xpath("//font/text()").get();
                        continue;
                    }
                }
                if (StringUtils.isEmpty(value)) {
                    value = trSelectable.xpath("//td/text()").nodes().get(j).get();
                }
                resultMap.put(j,StrUtil.trim(value));
                continue;

            } catch (Exception e) {
                log.error("爬取A股列表内容处理异常", e);
            }
        }
        log.info("A股列表内容全部处理结果:{}", resultMap);
        resultMap.forEach((key, value) -> {
            try {
                String code = ShareEnum.getCodeByKey(key);
                if (Objects.nonNull(code)) {
                    Field field = fieldMap.get(code);
                    if (Objects.nonNull(field)) {
                        Method method = methodMap.get(StrUtil.genSetter(field.getName()));
                        if (Objects.nonNull(method)) {
                            method.invoke(obj, StrUtil.trim(value));
                        }
                    }
                }
            } catch (Exception e) {
                log.error("A股列表处理异常", e);
            }
        });
        return obj;
    }
}
